<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>工厂模式终极版</title>
</head>

<body>


</body>
<script>
    //从FactoryPatten-ES5和FactoryPatten-ES6中我们会发现一个问题:
    //工厂方法中包含了很多与创建产品相关的过程，如果产品种类很多,这个工厂方法就会罗列很多产品的创建逻辑
    //每次新增或删除产品种类，不仅要增加产品类，还需要修改工厂方法，违反了开闭原则，导致这个工厂方法变得臃肿、高耦合

    //严格上这种实现在面向对象语言中叫做简单工厂模式。适用于产品种类较少，创建逻辑不复杂的时候使用

    //工厂模式的初衷：
    //工厂模式的本意是将实际创建对象的过程推迟到子类中，一般由抽象类作为父类，创建过程由抽象类的子类来具体实现
    //JavaScript中没有抽象类，所以我们可以简单地将工厂模式看做是一个实例化对象的工厂类即可

    //饭店方法
    class Restaurant {
        constructor() {
            this.menuData = {}
        }
        //新增菜品
        addMenu(menu, type, message) {
            if (this.menuData[menu]) {
                console.log('已经有这个菜了')
                return
            }
            this.menuData[menu] = { type, message }
        }

        // 创建菜品方法
        getMenu(menu) {
            if (!this.menuData[menu]) {
                throw new Error('本店没有这个菜')
            }
            const { type, message } = this.menuData[menu]
            return new Menu(type, message)
        }

        delMenu(menu){
            if(this.menuData[menu]){
                delete this.menuData[menu]
            }else{
                throw new Error('本店没有这个菜')
            }
        }
    }

    class Menu {
        constructor(type, message) {
            this.type = type
            this.message = message
        }
        eat() {
            console.log(this.type + this.message)
        }
    }

    const restaurant = new Restaurant()

    // 注册菜品
    restaurant.addMenu('YuXiangRouSi', '鱼香肉丝', '真香')
    restaurant.addMenu('MaPoDouFu', '麻婆豆腐', '好辣')

    // 删除菜品
    restaurant.delMenu('MaPoDouFu')

    const dash1 = restaurant.getMenu('MaPoDouFu')
    dash1.eat()

    const dash2 = restaurant.getMenu('KaiShuiBaiCai')
    // Error: 本店没有这个菜



    // 总结归纳:
    // Factory:工厂 负责返回产品实例
    // Product:产品 访问者从工厂拿到的产品实例
    // 设计思路：
    // 工厂定义产品数据库(Array or Object),提供新增产品和生成产品等方法，访问者生成工厂实例并通过工厂新增产品


</script>

</html>